//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package io.lumine.xikage.mythicmobs.skills.mechanics;

import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
import io.lumine.xikage.mythicmobs.adapters.AbstractLocation;
import io.lumine.xikage.mythicmobs.adapters.AbstractVector;
import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter;
import io.lumine.xikage.mythicmobs.io.MythicLineConfig;
import io.lumine.xikage.mythicmobs.logging.MythicLogger;
import io.lumine.xikage.mythicmobs.skills.*;
import io.lumine.xikage.mythicmobs.skills.projectiles.Projectile;
import io.lumine.xikage.mythicmobs.util.BlockUtil;
import io.lumine.xikage.mythicmobs.util.MythicUtil;
import io.lumine.xikage.mythicmobs.util.annotations.MythicMechanic;
import io.lumine.xikage.mythicmobs.utils.numbers.Numbers;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;

import java.util.HashSet;
import java.util.Iterator;

import static top.yunmouren.Entity.Entity.EntityBox;

@MythicMechanic(
        author = "Ashijin",
        name = "projectile",
        aliases = {"p"},
        description = "Launches a custom projectile at the target"
)
public class ProjectileMechanic extends Projectile implements ITargetedEntitySkill, ITargetedLocationSkill {
    protected ProjectileMechanic.ProjectileType type;
    protected float projectileGravity;
    protected boolean hugSurface;
    protected float heightFromSurface;

    public ProjectileMechanic(String skill, MythicLineConfig mlc) {
        super(skill, mlc);
        String type = mlc.getString("type", "NORMAL");
        this.type = ProjectileMechanic.ProjectileType.valueOf(type.toUpperCase());
        this.projectileGravity = mlc.getFloat(new String[]{"gravity", "g"}, 0.0F);
        this.hugSurface = mlc.getBoolean(new String[]{"hugsurface", "hs"}, false);
        this.heightFromSurface = mlc.getFloat(new String[]{"heightfromsurface", "hfs"}, 0.5F);
    }

    public boolean castAtLocation(SkillMetadata data, AbstractLocation target) {
        try {
            new ProjectileMechanic.ProjectileMechanicTracker(data, target.clone().add(0.0D, (double)this.targetYOffset, 0.0D));
            return true;
        } catch (Exception var4) {
            MythicLogger.error("An error occurred executing a Projectile Mechanic", var4);
            return false;
        }
    }

    public boolean castAtEntity(SkillMetadata data, AbstractEntity target) {
        return this.castAtLocation(data, target.getLocation().add(0.0D, target.getEyeHeight() / 2.0D, 0.0D));
    }

    protected static enum ProjectileType {
        NORMAL,
        METEOR;

        private ProjectileType() {
        }
    }

    public class ProjectileMechanicTracker extends ProjectileTracker {
        private float gravity = 0.0F;
        private AbstractLocation target;
        private int currentX;
        private int currentZ;

        public ProjectileMechanicTracker(SkillMetadata data, AbstractLocation target) {
            super(data, target);
            this.target = target;
            this.start();
        }

        public void projectileStart() {
            float velocity;
            if (ProjectileMechanic.this.type == ProjectileMechanic.ProjectileType.METEOR) {
                this.startLocation = this.target.clone();
                this.startLocation.add(0.0D, (double)ProjectileMechanic.this.heightFromSurface, 0.0D);
                if (ProjectileMechanic.this.projectileGravity <= 0.0F) {
                    this.gravity = ProjectileMechanic.this.projectileVelocity.get(this.data);
                    this.gravity = this.gravity > 0.0F ? this.gravity / ProjectileMechanic.this.ticksPerSecond : 0.0F;
                } else {
                    this.gravity = ProjectileMechanic.this.projectileGravity > 0.0F ? ProjectileMechanic.this.projectileGravity / ProjectileMechanic.this.ticksPerSecond : 0.0F;
                }

                velocity = 0.0F;
            } else {
                if (ProjectileMechanic.this.sourceIsOrigin) {
                    this.startLocation = this.data.getOrigin().clone();
                } else {
                    this.startLocation = this.data.getCaster().getEntity().getLocation().clone();
                }

                velocity = ProjectileMechanic.this.projectileVelocity.get(this.data) / ProjectileMechanic.this.ticksPerSecond;
                this.gravity = ProjectileMechanic.this.projectileGravity > 0.0F ? ProjectileMechanic.this.projectileGravity / ProjectileMechanic.this.ticksPerSecond : 0.0F;
                if (ProjectileMechanic.this.startYOffset != 0.0F) {
                    this.startLocation.setY(this.startLocation.getY() + (double)ProjectileMechanic.this.startYOffset);
                }

                if (ProjectileMechanic.this.startForwardOffset != 0.0F) {
                    this.startLocation = MythicUtil.move(this.startLocation, (double)ProjectileMechanic.this.startForwardOffset, 0.0D, 0.0D);
                }

                if (ProjectileMechanic.this.startSideOffset != 0.0F) {
                    this.startLocation = MythicUtil.move(this.startLocation, 0.0D, 0.0D, (double)ProjectileMechanic.this.startSideOffset);
                }
            }

            this.previousLocation = this.startLocation.clone();
            this.currentLocation = this.startLocation.clone();
            if (this.currentLocation != null) {
                this.currentVelocity = this.target.toVector().rotate(0.001F).subtract(this.currentLocation.toVector()).normalize();
                float noise;
                if (ProjectileMechanic.this.projectileVelocityHorizOffset != 0.0F || ProjectileMechanic.this.projectileVelocityHorizNoise > 0.0F) {
                    noise = 0.0F;
                    if (ProjectileMechanic.this.projectileVelocityHorizNoise > 0.0F) {
                        noise = (float)((double)ProjectileMechanic.this.projectileVelocityHorizNoiseBase + Numbers.randomDouble() * (double)ProjectileMechanic.this.projectileVelocityHorizNoise);
                    }

                    this.currentVelocity.rotate(ProjectileMechanic.this.projectileVelocityHorizOffset + noise);
                }

                if (ProjectileMechanic.this.projectileVelocityVertOffset != 0.0F || ProjectileMechanic.this.projectileVelocityVertNoise > 0.0F) {
                    noise = 0.0F;
                    if (ProjectileMechanic.this.projectileVelocityVertNoise > 0.0F) {
                        noise = (float)((double)ProjectileMechanic.this.projectileVelocityVertNoiseBase + Numbers.randomDouble() * (double)ProjectileMechanic.this.projectileVelocityVertNoise);
                    }

                    this.currentVelocity.add(new AbstractVector(0.0F, ProjectileMechanic.this.projectileVelocityVertOffset + noise, 0.0F)).normalize();
                }

                if (ProjectileMechanic.this.hugSurface) {
                    this.currentLocation.setY((double)((float)((int)this.currentLocation.getY()) + ProjectileMechanic.this.heightFromSurface));
                    this.currentVelocity.setY(0).normalize();
                }

                if (ProjectileMechanic.this.powerAffectsVelocity) {
                    this.currentVelocity.multiply(this.power);
                }

                this.currentVelocity.multiply(velocity);
                if (ProjectileMechanic.this.projectileGravity > 0.0F) {
                    this.currentVelocity.setY(this.currentVelocity.getY() - (double)this.gravity);
                }

            }
        }

        public void setVelocity(double value) {
            this.currentVelocity = this.currentVelocity.normalize().multiply(value);
        }

        public void modifyVelocity(double v) {
            this.currentVelocity = this.currentVelocity.multiply(v);
        }

        public void setGravity(float p) {
            this.gravity = p;
        }

        public void modifyGravity(float p) {
            this.gravity *= p;
        }

        public void projectileTick() {
            this.previousLocation = this.currentLocation.clone();
            this.currentLocation.add(this.currentVelocity);
            if (ProjectileMechanic.this.hugSurface) {
                if (this.currentLocation.getBlockX() != this.currentX || this.currentLocation.getBlockZ() != this.currentZ) {
                    Block b = BukkitAdapter.adapt(this.currentLocation.subtract(0.0D, (double)ProjectileMechanic.this.heightFromSurface, 0.0D)).getBlock();
                    int attempts;
                    boolean ok;
                    if (BlockUtil.isPathable(b, this)) {
                        attempts = 0;
                        ok = false;

                        while(attempts++ < 10) {
                            b = b.getRelative(BlockFace.DOWN);
                            if (!BlockUtil.isPathable(b, (ProjectileTracker) this)) {
//                                System.out.println("WARNING State notifications By Yun_Nan ");
                                ok = true;
                                break;
                            }

                            this.currentLocation.add(0.0D, -1.0D, 0.0D);
                        }

                        if (!ok) {
                            this.terminate();
                            return;
                        }
                    } else {
                        attempts = 0;
                        ok = false;

                        while(attempts++ < 10) {
                            b = b.getRelative(BlockFace.UP);
                            this.currentLocation.add(0.0D, 1.0D, 0.0D);
                            if (BlockUtil.isPathable(b)) {
                                ok = true;
                                break;
                            }
                        }

                        if (!ok) {
                            this.terminate();
                            return;
                        }
                    }

                    this.currentLocation.setY((double)((float)((int)this.currentLocation.getY()) + ProjectileMechanic.this.heightFromSurface));
                    this.currentX = this.currentLocation.getBlockX();
                    this.currentZ = this.currentLocation.getBlockZ();
                }
            } else if (ProjectileMechanic.this.projectileGravity != 0.0F) {
                this.currentVelocity.setY(this.currentVelocity.getY() - (double)(ProjectileMechanic.this.projectileGravity / ProjectileMechanic.this.ticksPerSecond));
            }

            if (ProjectileMechanic.this.stopOnHitGround && !BlockUtil.isPathable(BukkitAdapter.adapt(this.currentLocation).getBlock(), this)) {
                this.currentLocation = this.previousLocation;
                this.terminate();
            } else {
                if (this.bullet != null) {
                    this.applyBulletVelocity();
                }

                if (this.inRange != null && this.inRange.size() > 0) {
                    this.immune.entrySet().removeIf((entry) -> {
                        return (Long)entry.getValue() < System.currentTimeMillis() - 2000L;
                    });
                    Iterator var4 = this.inRange.iterator();

                    while(var4.hasNext()) {
                        AbstractEntity e = (AbstractEntity)var4.next();
//                        实体死亡 或者 实体框重叠 或者免疫攻击
//                        删除实体框重叠判定
                        if (!e.isDead() && !this.immune.containsKey(e)) {
                            this.targets.add(e);
                            this.immune.put(e, System.currentTimeMillis());
                            break;
                        }
                    }
                }

                if (ProjectileMechanic.this.onTickSkill.isPresent() && ((Skill)ProjectileMechanic.this.onTickSkill.get()).isUsable(this.data)) {
                    SkillMetadata sData = this.data.deepClone();
                    AbstractLocation location;
                    if (ProjectileMechanic.this.bulletType == BulletType.ARROW) {
                        location = this.previousLocation.clone();
                    } else {
                        location = this.currentLocation.clone();
                    }

                    HashSet<AbstractLocation> targets = new HashSet();
                    targets.add(location);
                    sData.setLocationTargets(targets);
                    sData.setOrigin(location);
                    ((Skill)ProjectileMechanic.this.onTickSkill.get()).execute(sData);
                }

                if (this.targets.size() > 0) {
                    this.doHit((HashSet)this.targets.clone());
                    if (ProjectileMechanic.this.stopOnHitEntity) {
                        this.terminate();
                    }
                }

                this.targets.clear();
            }
        }

        public void applyBulletVelocity() {
            AbstractLocation ol;
            if (ProjectileMechanic.this.bulletType == BulletType.ITEM) {
                ol = this.previousLocation.clone().subtract(0.0D, 0.35D, 0.0D);
                AbstractSkill.getPlugin().getVolatileCodeHandler().getEntityHandler().setItemPosition(this.bullet, ol);
                this.bullet.setVelocity(this.currentLocation.toVector().subtract(this.previousLocation.toVector()));
            } else if (ProjectileMechanic.this.bulletType == BulletType.ARROW) {
                this.bullet.setVelocity(this.currentLocation.toVector().subtract(this.bullet.getLocation().clone().toVector()).multiply(0.25D));
            } else if (ProjectileMechanic.this.bulletType == BulletType.MOB) {
                ol = this.currentLocation.clone().add(this.currentVelocity).subtract(0.0D, 1.35D, 0.0D);
                if (ProjectileMechanic.this.bulletSpin != 0.0F) {
                    float newSpinx = this.bullet.getLocation().getYaw() + ProjectileMechanic.this.bulletSpin;
                    ol.setYaw(newSpinx);
                } else if (ProjectileMechanic.this.bulletMatchDirection) {
                    ol.setDirection(this.currentVelocity);
                }

                this.bullet.teleport(ol);
            } else {
                this.bullet.setVelocity(this.currentLocation.toVector().subtract(this.bullet.getLocation().clone().toVector()).multiply(1));
                if (ProjectileMechanic.this.bulletSpin > 0.0F) {
                    float newSpin = this.bullet.getLocation().getYaw() + ProjectileMechanic.this.bulletSpin;
                    AbstractSkill.getPlugin().getVolatileCodeHandler().getEntityHandler().setEntityRotation(this.bullet, newSpin, newSpin);
                }
            }

        }

        private void doHit(HashSet<AbstractEntity> targets) {
            if (ProjectileMechanic.this.onHitSkill.isPresent()) {
                SkillMetadata sData = this.data.deepClone();
                sData.setEntityTargets(targets);
                sData.setOrigin(this.currentLocation.clone());
                if (((Skill)ProjectileMechanic.this.onHitSkill.get()).isUsable(sData)) {
                    ((Skill)ProjectileMechanic.this.onHitSkill.get()).execute(sData);
                }
            }

        }

        public void setCancelled() {
            this.terminate();
        }

        public boolean getCancelled() {
            return this.components.hasTerminated();
        }
    }
}
